package com.example.blog_system_ssm.common;

import org.springframework.stereotype.Component;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Component
public class SensitiveWordUtil {
    public static final int MinMatchTYpe = 1;//最小匹配规则，如：敏感词库["中国","中国人"]，语句："我是中国人"，匹配结果：我是[中国]人
    public static final int MaxMatchType = 2;//最大匹配规则，与上相反，匹配最大规则，即为我是[中国人]

    private static final String FILTER_WORDS = "[ _`~!@#$%^&()=|{}':;',\\\\[\\\\].<>/~！@#￥%……&（）——|{}【】‘；：”“’。，、？]|\\n|\\r|\\t";

    //敏感词集合
    public static HashMap sensitiveWordMap;

    //通过DFA构建敏感词库
    public synchronized void init(Set<String> sensitiveWordSet) {
        initSensitiveWordMap(sensitiveWordSet);
    }

    //DFA实际是通过Map套MAp实现
    private void initSensitiveWordMap(Set<String> sensitiveWordSet){
        sensitiveWordMap = new HashMap(sensitiveWordSet.size());
        String key;
        Map nowMap;
        Map<String, String> newWorMap;

        Iterator<String> iterator=sensitiveWordSet.iterator();
        while(iterator.hasNext()){
            key= iterator.next();
            // 指向集合的头部，初始位置
            nowMap=sensitiveWordMap;
            for(int i=0;i<key.length();++i){
                char keyChar = key.charAt(i);
                //库中获取关键字
                Object wordMap=nowMap.get(keyChar);
                if(wordMap!=null){
                    //将指向移动到此keyChar存在的位置
                    nowMap=(Map)wordMap;
                }else {
                    //不存在则，则构建一个map，同时将isEnd设置为0，由于他不是最后一个
                    newWorMap = new HashMap<>();
                    //不是最后一个
                    newWorMap.put("isEnd", "0");
                    nowMap.put(keyChar, newWorMap);
                    //指向移到下一个字符
                    nowMap = newWorMap;
                }
                if (i == key.length() - 1) {
                    //最后一个
                    nowMap.put("isEnd", "1");
                }
            }
        }
    }

    //判断文本是否包含敏感词，包含则返回true，否则返回false
    //可选择匹配模式
    public boolean contains(String txt, int matchType) {
        boolean flag = false;
        for (int i = 0; i < txt.length(); i++) {
            int matchFlag = checkSensitiveWord(txt, i, matchType); //判断是否包含敏感字符
            if (matchFlag > 0) {    //大于0存在，返回true
                flag = true;
            }
        }
        return flag;
    }

    //判断文本是否包含敏感词，包含则返回true，否则返回false
    //默认最大模式匹配
    public boolean contains(String txt) {
        return contains(txt, MaxMatchType);
    }


     //获取文本中的敏感词
     //可选择匹配模式
    public Set<String> getSensitiveWord(String txt, int matchType) {
        Set<String> sensitiveWordList = new HashSet<>();

        for (int i = 0; i < txt.length(); i++) {
            //判断是否包含敏感字符
            int length = checkSensitiveWord(txt, i, matchType);
            if (length > 0) {//存在,加入list中
                sensitiveWordList.add(txt.substring(i, i + length));
                i = i + length - 1;//由于for会自增所以-1
            }
        }

        return sensitiveWordList;
    }

    //获取文本中的敏感词
    //默认最大匹配
    public Set<String> getSensitiveWord(String txt) {
        return getSensitiveWord(txt, MaxMatchType);
    }

    //检查文本中是否包含敏感字符
    //存在则返回敏感词长度，否则返回0
    private int checkSensitiveWord(String txt, int beginIndex, int matchType){
        //敏感词结束标识位：用于敏感词只有1位的状况
        boolean flag = false;
        //匹配标识数默认为0
        int matchFlag = 0;
        //特殊字符数量
        int filterCount=0;
        //是否存在特殊字符
        boolean filterFlag=false;
        char word;
        Map nowMap=sensitiveWordMap;
        for(int i=beginIndex;i<txt.length();++i){
            word=txt.charAt(i);
            //处理特殊字符干扰屏蔽词
            if(isSpecialChar(String.valueOf(word))){
                filterFlag=true;
                filterCount++;
                continue;
            }
            nowMap=(Map)nowMap.get(word);
            if (nowMap != null) {//存在，则判断是否为最后一个
                //找到相应key，匹配标识+1
                matchFlag++;
                //若是为最后一个匹配规则,结束循环，返回匹配标识数
                if ("1".equals(nowMap.get("isEnd"))) {
                    //结束标志位为true
                    flag = true;
                    //最小规则，直接返回,最大规则还需继续查找
                    if (MinMatchTYpe == matchType) {
                        break;
                    }
                }
            } else {//不存在，直接返回
                break;
            }
        }
        if (matchFlag < 2 || !flag) {//长度必须大于等于1，为词
            matchFlag = 0;
        }
        if(flag&&filterFlag){
            return matchFlag+filterCount;
        }
        return matchFlag;
    }

    //敏感词替换
    public String replaceSensitiveWord(String txt, char replaceChar, int matchType) {
        String resultTxt = txt;
        //获取全部的敏感词
        Set<String> set = getSensitiveWord(txt, matchType);
        Iterator<String> iterator = set.iterator();
        String word;
        String replaceString;
        while (iterator.hasNext()) {
            word = iterator.next();
            replaceString = getReplaceChars(replaceChar, word.length());
            //由于replaceAll是将所有的敏感词替换成replaceString
            //所以要先将replaceChar转换成与敏感词相同长度的replaceString
            resultTxt = resultTxt.replaceAll(word, replaceString);
        }
        return resultTxt;
    }

    //获取要替换的字符串
    private String getReplaceChars(char replaceChar, int length) {
        String resultReplace = String.valueOf(replaceChar);
        for (int i = 1; i < length; i++) {
            resultReplace += replaceChar;
        }
        return resultReplace;
    }

    public boolean isSpecialChar(String str) {
        Pattern p = Pattern.compile(FILTER_WORDS);
        Matcher m = p.matcher(str);
        return m.find();
    }
}
